﻿////////////////////////////////////////////////////////////////////////
//                  Q - A B C   S O U N D   P L A Y E R
//
//                   Copyright (C) Pieter Geerkens 2012
////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Irony.Parsing;

namespace PGSoftwareSolutionsInc.PGIrony {
	/// <summary>Options AllowLetterAfter and IntOnly set automatically.</summary>
	/// <typeparam name="TValue"></typeparam>
	public class MusicIntegerLiteral<TValue> : NumberLiteral {
		public MusicIntegerLiteral(string name) //, NumberOptions options) 
		: base(name,NumberOptions.AllowLetterAfter | NumberOptions.IntOnly) {
			TypeCode typeCode		= Type.GetTypeCode(GetType().GetGenericArguments()[0]
											.UnderlyingSystemType);
			DefaultIntTypes		= new TypeCode[] {typeCode};
			AstConfig.NodeType	= typeof(LiteralValueNode<TValue>);
		}
	}

	/// <summary> RegexBasedTerminal sub-class that parses the constants of enumeration <i>TValue</i> 
	/// in determining the Value of the Terminal.
	/// </summary>
	/// <typeparam name="TValue">Must be an <i>Enum</i> type, but only enforced at run-time
	/// as a constraint like <i>TValue : System.Enum</i> is forbidden.</typeparam>
	public class RegexEnumTerm<TValue> : RegexBasedTerminal where TValue : struct {
	/// <summary> RegexBasedTerminal sub-class that parses the constants of enumeration <i>TValue</i> 
	/// in determining the Value of the Terminal.
	/// </summary>
		public RegexEnumTerm(string pattern, Func<string,TValue> fromString = null) 
			: base(pattern) {
			EnumType					= GetType().GetGenericArguments()[0].UnderlyingSystemType;
			if (fromString == null && !EnumType.IsEnum) throw new ArgumentOutOfRangeException(
					"T",EnumType.Name, "Generic argument must be Enum type when fromString is null.");
			Name						= EnumType.Name;
			FromString				= fromString;
			AstConfig.NodeType	= typeof(LiteralValueNode<TValue>);
		}

		protected Func<string,TValue> FromString	{ get; set; }
		protected Type						EnumType		{ get; set; }
		protected virtual TValue ConvertValue(ParsingContext context, string textValue) {
			return (FromString == null) ? (TValue)System.Enum.Parse(EnumType,textValue.ToUpper())
												 : FromString(textValue);
		}

		public override Token TryMatch(ParsingContext context, ISourceStream source) {
			Token token = base.TryMatch(context, source);
			if (token != null) 	token.Value = ConvertValue(context,token.ValueString);
			return token;
		}
	}

	public class MyKeyTerm : KeyTerm {
		/// <summary>
		/// A <i>KeyTerm</i>(inal) implementation that automatically sets <i>AllowAlphaAfterKeyword</i>.
		/// </summary>
		public MyKeyTerm(string text, string name, bool allowAlphaAfterKeyword = true)
			: base(text,name) { 
			AllowAlphaAfterKeyword = allowAlphaAfterKeyword; 
		}
	}
}
